package com.zx.scp.service.impl;

import com.zx.map.service.model.PayCmbModel;
import com.zx.map.service.model.PayCmbResponseModel;
import com.zx.scp.service.PayCmbService;
import com.zx.scp.service.model.QueryCmbModel;
import com.zx.scp.service.model.QueryCmbResponseModel;
import com.zx.scp.service.util.cmb.XmlPacket;
import com.zx.scp.utils.PropertyUtil;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;

import java.io.*;
import java.net.*;
import java.util.Map;
import java.util.Properties;

/**
 * Created by IntelliJ IDEA. User: Administrator Date: 15-5-31 Time: 上午10:26 To
 * change this template use File | Settings | File Templates.
 */
@Component("payCmbService")
public class PayCmbServiceImpl implements PayCmbService {
    /**
     * log
     */
    private static Logger log = Logger.getLogger(PayCmbServiceImpl.class);


    /**
     * 支付
     *
     * @param payCmbRequest
     */
    public PayCmbResponseModel getPayResponse(PayCmbModel payCmbRequest) {
        // 生成请求报文
        String data = this.getPayRequestStr(payCmbRequest);
        // 连接前置机，发送请求报文，获得返回报文
        String result = this.sendRequest(data);
        // 处理返回的结果
        return this.processPayResult(result);
    }
    
    /**
     * 查询支付信息
     *
     * @param queryCmbModel
     */
    public QueryCmbResponseModel queryPayInfoResponse(QueryCmbModel queryCmbModel) {
        // 生成请求报文
        String data = this.getQueryCmbRequestStr(queryCmbModel);
        // 连接前置机，发送请求报文，获得返回报文
        String result = this.sendRequest(data);
        // 处理返回的结果
        return this.processQueryResult(result);
    }

    /**
     * 生成支付请求报文
     *
     * @return
     */
    private String getPayRequestStr(PayCmbModel payCmbRequest) {
        // 构造支付的请求报文
        XmlPacket xmlPkt = new XmlPacket("Payment", PropertyUtil.getValue("TRADEOPERATOR"));
        Map<Object, Object> mpPodInfo = new Properties();
        mpPodInfo.put("BUSCOD", "N02031");//业务类别 N02030:支付      N02031:直接支付		N02040:集团支付 		N02041:直接集团支付
        mpPodInfo.put("BUSMOD", "00001");//	业务模式编号
        xmlPkt.putProperty("SDKPAYRQX", mpPodInfo);
        Map<Object, Object> mpPayInfo = new Properties();
        mpPayInfo.put("YURREF", payCmbRequest.getOrderId());//业务参考号
        mpPayInfo.put("DBTACC", PropertyUtil.getValue("DBTACC")); //付方帐号
        mpPayInfo.put("DBTBBK", PropertyUtil.getValue("DBTBBK")); //	付方开户地区代码
        mpPayInfo.put("TRSAMT", payCmbRequest.getTradeAmt());//交易金额   单位元
        mpPayInfo.put("CCYNBR", PropertyUtil.getValue("CCYNBR")); //币种代码 暂时只支持10-人民币
        mpPayInfo.put("STLCHN", "F"); //结算方式代码结算方式代码 N：普通 F：快速     只对跨行交易有效；同行都是实时到账
        mpPayInfo.put("NUSAGE", "支付");  //用途
        mpPayInfo.put("CRTACC", payCmbRequest.getCardNo()); //收方帐号
        mpPayInfo.put("CRTNAM", payCmbRequest.getCardName());//收方帐户名
        mpPayInfo.put("BNKFLG", "N");//	系统内外标志		Y：招行；N：非招行；
        mpPayInfo.put("CRTBNK", payCmbRequest.getBankName());   //收方开户行
        mpPayInfo.put("CRTPVC", "上海");   //收方省份
        mpPayInfo.put("CRTCTY", "上海"); //收方城市
        xmlPkt.putProperty("SDKPAYDTX", mpPayInfo);
        String data=xmlPkt.toXmlString();
        log.info("出款信息:" +data );
        return data;
    }
    
    /**
     * 生成查询请求报文
     *
     * @return
     */
    private String getQueryCmbRequestStr(QueryCmbModel queryCmbModel) {
        // 构造支付查询的请求报文
        XmlPacket xmlPkt = new XmlPacket("GetPaymentInfo", PropertyUtil.getValue("TRADEOPERATOR"));
        Map<Object, Object> mpPodInfo = new Properties();
        mpPodInfo.put("BGNDAT", queryCmbModel.getBeginDate());//	起始日期
        mpPodInfo.put("ENDDAT", queryCmbModel.getBeginDate());//	终止日期
        mpPodInfo.put("YURREF", queryCmbModel.getOrderId());//	业务订单号
        xmlPkt.putProperty("SDKPAYQYX", mpPodInfo);
        log.info("交易查询信息:" + xmlPkt.toXmlString());
        return xmlPkt.toXmlString();
    }

    /**
     * 连接前置机，发送请求报文，获得返回报文
     *
     * @param data
     * @return
     * @throws MalformedURLException
     */
    private String sendRequest(String data) {
        String result = "";
        try {
            URL url;
            String urlFront = PropertyUtil.getValue("cmbFrontUrl");// 招行前置访问入口
            url = new URL(urlFront);
            HttpURLConnection conn;
            conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("POST");
            conn.setDoInput(true);
            conn.setDoOutput(true);
            OutputStream os;
            os = conn.getOutputStream();
            os.write(data.toString().getBytes("gbk"));
            os.close();
            BufferedReader br = new BufferedReader(new InputStreamReader(conn
                    .getInputStream()));
            String line;
            while ((line = br.readLine()) != null) {
                result += line;
            }
            log.info("出款返回信息:" + result);
            br.close();
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (ProtocolException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 处理返回的结果
     *   首先根据Payment返回报文INFO接口的RETCOD（或者Payment API返回值）进行判断：0表示本次交易通讯成功。需要接下来进行(2)的判断。
             -9和-1时，表示交易可疑，请查询支付结果。
             其他数值，表示交易失败。
         如果交易通讯成功则判断返回信息中REQSTS=’FIN’ 并且 RTNFLG=’F’，表示支付失败；否则表示支付已被银行受理
         （注意：支付请求的返回并非表示支付成功，支付是否成功一定要查询支付结果后才能取得）
     * @param result
     */
    private PayCmbResponseModel processPayResult(String result) {
    	PayCmbResponseModel payCmbResponseModel = new PayCmbResponseModel();
        if (result != null && result.length() > 0) {
            XmlPacket pktRsp = XmlPacket.valueOf(result);
            if (pktRsp != null) {
                String sRetCod = pktRsp.getRETCOD();
                if (sRetCod.equals("0")) { //首先根据Payment返回报文INFO接口的RETCOD（或者Payment API返回值）进行判断：0表示本次交易通讯成功
                    Map<Object, Object> propPayResult = pktRsp.getProperty("NTQPAYRQZ", 0);
                    //AUT	等待审批   NTE	终审完毕   WCF	订单待确认（商务支付用）   BNK	银行处理中         FIN	完成         ACK	等待确认(委托贷款用)
                    //APD 	待银行确认(国际业务用)                    OPR	数据接收中（代发）
                    String sREQSTS = (String) propPayResult.get("REQSTS");
                    String sRTNFLG = (String) propPayResult.get("RTNFLG");//REQSTS=FIN时，RTNFLG才有意义
                    String sREQNBR = (String) propPayResult.get("REQNBR");//流程实例号
                    payCmbResponseModel.setOrderId((String) propPayResult.get("YURREF"));//返回我方订单号
                    payCmbResponseModel.setCmbOrderId(sREQNBR);
                    //S	成功	银行支付成功
                    //F	失败	银行支付失败
                    //B	退票	银行支付被退票
                    //R	否决	企业审批否决
                    //D	过期	企业过期不审批
                    //C	撤消	企业撤销
                    //M	商户撤销订单	商务支付
                    //V	拒绝	委托贷款被借款方拒绝
                    if (sREQSTS.equals("FIN") && sRTNFLG.equals("F")) {// 如果交易通讯成功则判断返回信息中REQSTS=’FIN’ 并且 RTNFLG=’F’，表示支付失败；否则表示支付已被银行受理
                        log.info("出款失败："
                                + propPayResult.get("ERRTXT"));
                        payCmbResponseModel.setReturnCode("9000");
                        payCmbResponseModel.setErrMsg(propPayResult.get("ERRTXT").toString());
                    } else {
                        log.info("出款已被银行受理（出款状态：" + sREQSTS + "）");
                        payCmbResponseModel.setReturnCode("0000");   
                        payCmbResponseModel.setErrMsg("支付成功");
                    }
                } else if (sRetCod.equals("-9") || sRetCod.equals("-1")) {//-9和-1时，表示交易可疑，请查询支付结果
                    log.info("出款未知异常，请查询支付结果确认支付状态，错误信息："
                            + pktRsp.getERRMSG());
                    payCmbResponseModel.setReturnCode("0000");
                    payCmbResponseModel.setErrMsg("出款待确认"+pktRsp.getERRMSG());
                } else { //其他数值，表示交易失败
                    log.info("出款失败：" + pktRsp.getERRMSG());
                    payCmbResponseModel.setReturnCode("9000");
                    payCmbResponseModel.setErrMsg("出款失败"+pktRsp.getERRMSG());
                }
            } else {
                log.info("响应报文解析失败");
                payCmbResponseModel.setReturnCode("9999");
                payCmbResponseModel.setErrMsg("响应报文解析失败");
            }
        }else{
        	payCmbResponseModel.setReturnCode("9999");
        	payCmbResponseModel.setErrMsg("出款失败");
        }
        return payCmbResponseModel;
    }
    
    
    /**
     * 处理返回的结果
     *
     * @param result
     */
    private QueryCmbResponseModel processQueryResult(String result) {
    	QueryCmbResponseModel queryCmbResponseModel = new QueryCmbResponseModel();
        if (result != null && result.length() > 0) {
            XmlPacket pktRsp = XmlPacket.valueOf(result);
            if (pktRsp != null) {
                String sRetCod = pktRsp.getRETCOD();
                if (sRetCod.equals("0")) {
                    Map<Object, Object> propQueryResult = pktRsp.getProperty("NTQPAYQYZ", 0);
                    //AUT	等待审批   NTE	终审完毕   WCF	订单待确认（商务支付用）   BNK	银行处理中         FIN	完成         ACK	等待确认(委托贷款用)
                    //APD 	待银行确认(国际业务用)                    OPR	数据接收中（代发）
                    String sREQSTS = (String) propQueryResult.get("REQSTS");
                    String sRTNFLG = (String) propQueryResult.get("RTNFLG");//REQSTS=FIN时，RTNFLG才有意义
                    //S	成功	银行支付成功
                    //F	失败	银行支付失败
                    //B	退票	银行支付被退票
                    //R	否决	企业审批否决
                    //D	过期	企业过期不审批
                    //C	撤消	企业撤销
                    //M	商户撤销订单	商务支付
                    //V	拒绝	委托贷款被借款方拒绝
                    if (sREQSTS.equals("FIN") && sRTNFLG.equals("S")) {//
                        log.info("查询支付信息成功");
                        queryCmbResponseModel.setReturnCode("0000");
                    } else {
                        log.info("查询支付信息成功");
                        queryCmbResponseModel.setReturnCode("0000");                        
                    }
                } else if (sRetCod.equals("-9")) {
                    log.info("查询支付信息成功未知异常，请查询支付结果确认支付状态，错误信息："
                            + pktRsp.getERRMSG());
                    queryCmbResponseModel.setReturnCode("9999");
                } else {
                    log.info("查询支付信息成功失败：" + pktRsp.getERRMSG());
                    queryCmbResponseModel.setReturnCode("9999");
                }
            } else {
                log.info("响应报文解析失败");
                queryCmbResponseModel.setReturnCode("9999");
            }
        }else{
        	queryCmbResponseModel.setReturnCode("9999");
        }
        return queryCmbResponseModel;
    }

    public static void main(String[] args) {
	        try {
	        	PayCmbServiceImpl request = new PayCmbServiceImpl();
	        	QueryCmbModel payCmbRequest = new QueryCmbModel();
	        	payCmbRequest.setBeginDate("20151123");
	        	payCmbRequest.setOrderId("201511230001");
	            // 生成请求报文
	            String data = request.getQueryCmbRequestStr(payCmbRequest);
	            // 连接前置机，发送请求报文，获得返回报文
	            String result = request.sendRequest(data);
	            // 处理返回的结果
	            request.processQueryResult(result);
	        } catch (Exception e) {
	            System.out.println(e.getMessage());
	        }
    }

}
